﻿<# 
.SYNOPSIS 
    Invokes a PSAdmin command.
.DESCRIPTION 
    Use this command to invoke the psadmin.exe executable with the correct environment.
.NOTES 
    File Name  : Invoke-PSAdmin.ps1 
    Author     : Scott Kearney - scott@kearney.tk 
    Requires   : PowerShell V3 
.EXAMPLE 
    Invoke-PSAdmin -PS_HOME $PS_HOME -PS_CFG_HOME $PS_CFG_HOME -ServerType AppServer -Domain "DOMAIN1" -Command "-c boot -d DOMAIN1"
    Starts the domain named DOMAIN1.
.PARAMETER PS_HOME
    The full path to the PS_HOME directory for this domain.
.PARAMETER PS_CFG_HOME
    The full path to the PS_CFG_HOME directory for this domain.
.PARAMETER ServerType
    The type of server on which to perform the action.
.PARAMETER Domain
    The name of the domain on which to perform the action.
.PARAMETER Command
    The command line arguments to pass to the psadmin.exe program.
    See the related link for a list of psadmin.exe commands.
.PARAMETER ExtraCommands
    Any other parameters to the PSAdmin that should be added.
.PARAMETER AsJob
    If specified, will run the command as a job instead.
.OUTPUTS
    System.Collections.Hashtable
.LINK
    Using the PSADMIN Command-Line Interface
    http://docs.oracle.com/cd/E41633_01/pt853pbh1/eng/pt/tsvt/task_UsingthePSADMINCommand-LineInterface-c07e70.html
#> 
function Invoke-PSAdmin
{
    [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='High')]
    [OutputType([Hashtable])]
    Param
    (
        # The full path to the PS_HOME directory for this domain.
        # See http://docs.oracle.com/cd/E41633_01/pt853pbh1/eng/pt/tsvt/concept_UnderstandingPS_HOMEandPS_CFG_HOME-eb7ece.html
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The full path to the PS_HOME directory for this domain.",
                   Position=0)]
        [ValidateScript({Validate_PS_HOME $_})]
        [String]
        $PS_HOME,

        # The full path to the PS_CFG_HOME directory for this domain.
        # See http://docs.oracle.com/cd/E41633_01/pt853pbh1/eng/pt/tsvt/concept_UnderstandingPS_HOMEandPS_CFG_HOME-eb7ece.html
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The full path to the PS_CFG_HOME directory for this domain.",
                   Position=1)]
        [ValidateScript({Validate_PS_CFG_HOME $_})]
        [String]
        $PS_CFG_HOME,

        # The type of server on which to perform the action.
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The type of server on which to perform the action.",
                   Position=2)]
        [ValidateSet("AppServer","PrcsScheduler")]
        $ServerType,

        # The name of the domain on which to perform the action.
        # Should be a directory under the PS_CFG_HOME
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The name of the domain on which to perform the action.",
                   Position=3)]
        #[ValidateScript({Validate_Domain $PS_CFG_HOME $ServerType $_})]
        [String]
        $Domain,

        # The command which will be executed through PSAdmin
        # This string will be passed as an argument to PSAdmin.
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=4)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Command,

        # Any other parameters to PSAdmin that should be added.
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=5)]
        [String]
        $ExtraCommands,

        # If specified, will run the command as a job instead.
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=6)]
        [Switch]
        $AsJob
    )

    Begin
    {
    }
    Process
    {
        # Set up variables
        $result = $null
        $return = $null

        # Set up required environment variables
        $env:PS_HOME = $PS_HOME
        $env:PS_CFG_HOME = $PS_CFG_HOME

        switch ($ServerType)
        {
            'AppServer'     {$serverTypeCommand = "-c"}
            'PrcsScheduler' {$serverTypeCommand = "-p"}
            'PIA'           {$serverTypeCommand = "-w"}
            'SearchServer'  {$serverTypeCommand = "-s"}
        }

        $PSAdminArguments = "$serverTypeCommand $Command -d $Domain $ExtraCommands"

        # Run the command, passing the $Command as an argument to the executable
        # The operator "*>&1" will redirect all streams to the first. This will pass
        # the errors from psadmin.exe to the variable, which can then be parsed.
        Write-Verbose "Running: $env:PS_HOME\appserv\psadmin.exe $PSAdminArguments *>&1"
        
        if($AsJob)
        {
            # Start the command as a job.
            $result = Start-Job {
                param($PSAdminArguments)
                Invoke-Expression "$env:PS_HOME\appserv\psadmin.exe $PSAdminArguments *>&1"
            } -ArgumentList $PSAdminArguments

            Write-Verbose "Job ID: $($result.Id)"

            # Return right away - the calling process will be responsible for parsing output directly.
            return $result
        }
        else
        {
            # AsJob not specified, run as a normal command.
            $result = Invoke-Expression "$env:PS_HOME\appserv\psadmin.exe $PSAdminArguments *>&1"
        }

        # Parse out the results, based on String and non-String (usually Error) types.
        $return = @{
            Result = ($result | where {$_.GetType() -like "String"});
            Error = ((($result | where {$_.GetType() -notlike "String"} ) -join "") -split "`n");
        }
        
        Write-Verbose "*** Errors ***"
        $return.Error | %{ Write-Verbose $_ }
        
        Write-Verbose "*** Results ***"
        $return.Result | %{ Write-Verbose $_ }

        Write-Verbose "Exit code: $LASTEXITCODE"

        # Exit Codes
        #   10 : Improper arguments passed (shows usage)
        #  275 : Invalid Template for domain creation! (create)

        return $return
    }
    End
    {
    }
}